/**
 * desc:
 * User: zhitao.guo@leweipai.cn
 * Date: 2021/8/16
 * Time: 15:41
 */

class Snake {
    // 表示蛇头的元素
    head: HTMLElement;
    // 蛇的身体(包括蛇头)
    bodies: HTMLCollection;

    // 获取蛇的容器
    element: HTMLElement;
    constructor() {
        // 获取蛇头元素
        this.element = document.getElementById('snake')!
        this.head = document.querySelector('#snake > div') as HTMLElement;
        this.bodies = this.element.getElementsByTagName('div');
    }

    // 获取蛇的坐标(蛇头的坐标)
    get X () {
        return this.head.offsetLeft;
    }
    // 获取蛇的 y轴坐标
    get Y () {
        return this.head.offsetTop;
    }

    // 设置蛇头的坐标
    set X (value) {
        // 如果新值和旧的值一样则不更改
        if (this.X === value) {
            return;
        }
        // X的合法值0-290
        if (value < 0 || value > 290) {
            // 进入判断说明蛇撞墙了 抛出异常
            throw new Error('蛇撞墙了')
        }
        // 修改X的時候是水平坐标，蛇在左右移动，蛇在向左移动的时候不能向右掉头，反之亦然
        if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
            // r如果发生了掉头，让蛇向反方向移动
            if(value > this.X) {
                // 如果新值 value 大于 旧值， 则说明蛇在向右走，发生掉头的时候应该继续向左走
                value = this.X - 10;
            } else {
                // 向左走
                value = this.X + 10;
            }
        }
        this.moveBody();
        this.head.style.left = value + 'px';
        this.checkHeadBody();
    }

    set Y (value) {
        if(this.Y === value) {
            return;
        }
        // Y的合法值0-290
        if(value < 0 || value > 290) {
            // 进入判断说明蛇撞墙了 抛出异常
            throw new Error('蛇撞墙了')
        }
        // 修改Y的時候是垂直坐标，蛇在上下移动，蛇在向下移动的时候不能向上掉头，反之亦然
        if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
            // r如果发生了掉头，让蛇向反方向移动
            if(value > this.Y) {
                // 如果新值 value 大于 旧值， 则说明蛇在向下走，发生掉头的时候应该继续向左走
                value = this.Y - 10;
            } else {
                // 向左走
                value = this.Y + 10;
            }
        }
        this.moveBody();
        this.head.style.top = value + 'px';
        this.checkHeadBody();
    }

    // 蛇增加身体的方法
    addBody () {
        // 向element中添加一个div
        this.element.insertAdjacentHTML("beforeend", "<div></div>")
    }

    // 添加一个蛇身体移动的方法
    moveBody () {
        /**
         * 将后面的身体设置为前边身体的位置
         *  举例子
         *      第4节 = 第3节的位置
         *      第3节 = 第2节的位置
         *      第2节 = 蛇头的位置
         */
        // 遍历获取所有的身体
        for(let i = this.bodies.length - 1; i > 0; i --) {
            // 获取前边身体的位置
            let X = (this.bodies[i - 1] as HTMLElement).offsetLeft;
            let Y = (this.bodies[i - 1] as HTMLElement).offsetTop;
            // 将这个值设置到当前的身体
            (this.bodies[i] as HTMLElement).style.left = X + 'px';
            (this.bodies[i] as HTMLElement).style.top = Y + 'px';
        }

    }

    // 检查蛇头是否撞到身体
    checkHeadBody () {
        // 获取所有的身体，检查是否和蛇头的坐标发生重叠
        for(let i = 1; i < this.bodies.length; i ++) {
            let bd = (this.bodies[i] as HTMLElement);
            if(this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
                // 进入判断说明蛇头撞到了身体，游戏结束
                throw new Error('撞到了自己！');
            }
        }
    }
}

export default Snake;
